package org.liaohailong.victorlibrary.widget

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import android.view.animation.AccelerateInterpolator

/**
 * Author: liaohailong
 * Date: 2020/9/15
 * Time: 21:30
 * Description: 红包界面 - 开场动画
 **/
class RedPacketEnterAnimView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
        View(context, attrs, defStyleAttr) {
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context) : this(context, null)

    private val topPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL_AND_STROKE
    }
    private val bottomPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.FILL_AND_STROKE
    }

    private val topPath = Path()
    private val bottomPath = Path()
    private val topRect = Rect()
    private val bottomRect = Rect()
    private var topOffset = 0
    private var bottomOffset = 0

    var startColor: Int = Color.YELLOW
    var endColor: Int = Color.RED
    private var topMinHeightPercent: Float = 0.8f
    private var topFirstHeightPercent: Float = 0f
    var onAnimRunningCallback: OnAnimRunningCallback? = null

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        prepare()
    }

    private fun prepare() {
        val w = measuredWidth
        val h = measuredHeight

        // 设置顶部的显示形状
        val radius = h * topFirstHeightPercent
        val centerX = w / 2f
        val centerY = 0f
        topPath.reset()
        topPath.addCircle(centerX, centerY, radius, Path.Direction.CW)
        topRect.set(0, 0, (centerX + radius).toInt(), (centerY + radius).toInt())

        // 设置底部的显示形状
        bottomPath.reset()
        bottomPath.addRect(0f, 0f, w.toFloat(), h.toFloat(), Path.Direction.CW)
        bottomPath.op(topPath, Path.Op.DIFFERENCE)
        val resultPow = Math.pow(radius.toDouble(), 2.toDouble()) - Math.pow((w / 2f).toDouble(), 2.toDouble())
        val heightAnchor = Math.sqrt(resultPow).toInt()
        bottomRect.set(0, heightAnchor, w, h)

        // 设置顶部画笔内容
        val x0 = 0f
        val y0 = 0f
        val x1 = centerX + radius
        val y1 = centerY + radius
        val color0 = startColor
        val color1 = endColor
        val tile: Shader.TileMode = Shader.TileMode.CLAMP
        topPaint.shader = LinearGradient(x0, y0, x1, y1, color0, color1, tile)

        // 设置底部画笔内容
        bottomPaint.color = endColor

        // 控制顶部区域最低中心锚点
        val x = measuredWidth / 2
        val y = topRect.bottom + topOffset
        onAnimRunningCallback?.onAnchorUpdate(x, y, 0.0f)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.apply {
            drawTop(this)
            drawBottom(this)
        }
    }

    private fun drawTop(canvas: Canvas) {
        canvas.save()
        canvas.translate(0f, topOffset.toFloat())
        canvas.drawPath(topPath, topPaint)
        canvas.restore()
    }

    private fun drawBottom(canvas: Canvas) {
        canvas.save()
        canvas.translate(0f, bottomOffset.toFloat())
        canvas.drawPath(bottomPath, bottomPaint)
        canvas.restore()
    }

    /**
     * 初始化配置
     * @param startColor 左上角颜色
     * @param endColor 右下角颜色
     * @param topFirstHeightPercent 初始化高度位置
     * @param topMinHeightPercent 顶部最低高度
     * @param onAnimRunningCallback 动画执行回调 - 锚点坐标
     */
    fun init(startColor: Int,
             endColor: Int,
             topFirstHeightPercent: Float,
             topMinHeightPercent: Float,
             onAnimRunningCallback: OnAnimRunningCallback) {
        this@RedPacketEnterAnimView.startColor = startColor
        this@RedPacketEnterAnimView.endColor = endColor
        this@RedPacketEnterAnimView.topFirstHeightPercent = topFirstHeightPercent
        this@RedPacketEnterAnimView.topMinHeightPercent = topMinHeightPercent
        this@RedPacketEnterAnimView.onAnimRunningCallback = onAnimRunningCallback
        post {
            prepare()
            invalidate()
        }
    }

    fun start(_duration: Long = 300L) {
        topOffset = 0
        bottomOffset = 0
        ValueAnimator.ofFloat(0.0f, 1.0f).apply {
            duration = _duration
            interpolator = AccelerateInterpolator()
            addUpdateListener {
                val progress = it.animatedValue as Float
                val topOffsetLength = topRect.height() * (1.0f - topMinHeightPercent)
                val bottomHeight = bottomRect.height()

                topOffset = -(topOffsetLength * progress).toInt()
                bottomOffset = (bottomHeight * progress).toInt()

                // 控制顶部区域最低中心锚点
                val x = measuredWidth / 2
                val y = topRect.bottom + topOffset
                onAnimRunningCallback?.onAnchorUpdate(x, y, progress)

                // 重绘视图
                invalidate()
            }
        }.start()
    }

    interface OnAnimRunningCallback {
        fun onAnchorUpdate(x: Int, y: Int, progress: Float)
    }
}